﻿@using System.Reflection
@using AntDesign.TableModels
@inherits BaseComponent
@typeparam TItem where TItem : class, new()

<AntTable @ref="table" TItem="TItem" Context="Context" Model="Model"
          ScrollX="@scrollX" ScrollY="@scrollY" Loading="isQuering"
          @bind-SelectedRows="Model.SelectedRows" OnChange="OnChange" OnRowClick="OnRowClick">
    @if (Model.SelectType != TableSelectType.None)
    {
        <Selection Type="@Model.SelectType.ToString().ToLower()" Align="ColumnAlign.Center" Width="50" Class="kui-table-check" />
    }
    @if (Model.Columns != null && Model.Columns.Count > 0)
    {
        var isDictionary = Model.IsDictionary;
        foreach (var item in Model.Columns)
        {
            if (!item.IsVisible)
                continue;

            var title = Language?.GetString<TItem>(item);
            var width = item.Width > 0 ? item.Width.ToString() : "";
            RenderFragment<TItem> template = null;
            Model.Templates?.TryGetValue(item.Id, out template);
            if (isDictionary)
            {
                var value = (context as Dictionary<string, object>).GetValue(item.Id);
                <DictionaryColumn Title="@title" Property="c=>c.GetValue(item.Id)" Width="@width"
                                  Ellipsis ShowSorterTooltip="false" Fixed="@item.Fixed"
                                  Sortable="item.IsSort" DefaultSortOrder="item.ToSortDirection()"
                                  Align="@GetColumnAlign(item.Align)">
                    @if (template != null)
                    {
                        @template(context)
                    }
                    else if (item.Type == FieldType.Switch)
                    {
                        var isChecked = Utils.ConvertTo<bool>(value);
                        <Switch Disabled Value="isChecked" />
                    }
                    else if (item.IsViewLink)
                    {
                        <span class="kui-link" @onclick="e=>Model.ViewForm(context)">@value</span>
                    }
                    else
                    {
                        @GetColumnText(item, value)
                    }
                </DictionaryColumn>
            }
            else
            {
                var value = TypeHelper.GetPropertyValue(context, item.Id);
                <Column Title="@title" DataIndex="@item.Id" TData="object" Width="@width"
                        Ellipsis ShowSorterTooltip="false" Fixed="@item.Fixed"
                        Sortable="item.IsSort" DefaultSortOrder="item.ToSortDirection()"
                        Align="@GetColumnAlign(item.Align)">
                    <TitleTemplate>
                        @if (!string.IsNullOrWhiteSpace(item.Tooltip))
                        {
                            <Tooltip Title="@item.Tooltip">@title</Tooltip>
                        }
                        else
                        {
                            @title
                        }
                    </TitleTemplate>
                    <ChildContent>
                        @if (template != null)
                        {
                            @template(context)
                        }
                        else if (item.Type == FieldType.Switch)
                        {
                            var isChecked = Utils.ConvertTo<bool>(value);
                            <Switch Disabled Value="isChecked" />
                        }
                        else if (item.IsViewLink)
                        {
                            <span class="kui-link" @onclick="e=>Model.ViewForm(context)">@value</span>
                        }
                        else
                        {
                            @GetColumnText(item, value)
                        }
                    </ChildContent>
                </Column>
            }
        }
    }
    @if (Model.HasAction)
    {
        var actions = Model.RowActions?.Invoke(context);
        if (actions == null)
            actions = Model.Actions;
        Model.UpdateRowActions?.Invoke(context, actions);
        actions = actions.Where(a => a.Visible).ToList();
        actions.ForEach(d => d.Name = Language.GetString(d));
        <ActionColumn Title="@Language["Title.Action"]" Align="ColumnAlign.Center" Width="@Model.ActionWidth" Class="kui-table-action">
            @if (actions.Count > Model.ActionCount)
            {
                var takes = actions.Skip(0).Take(Model.ActionCount - 1).ToList();
                var mores = actions.Skip(Model.ActionCount - 1).ToList();
                foreach (var item in takes)
                {
                    <Tag Color="@GetActionColor(item.Style)" OnClick="e=>Model.OnAction?.Invoke(item, context)">@item.Name</Tag>
                }
                <AntDropdown Context="Context" Text="@Language["Button.More"]" Items="mores" OnItemClick="e=>Model.OnAction?.Invoke(e, context)" />
            }
            else
            {
                foreach (var item in actions)
                {
                    <Tag Color="@GetActionColor(item.Style)" OnClick="e=>Model.OnAction?.Invoke(item, context)">@item.Name</Tag>
                }
            }
        </ActionColumn>
    }
    @if (Model.HasSum)
    {
        <SummaryRow>
            @if (Model.SelectType != TableSelectType.None)
            {
                <SummaryCell Class="kui-table-check" Align="ColumnAlign.Center">@Language["IsSum"]</SummaryCell>
            }
            @if (Model.Columns != null && Model.Columns.Count > 0)
            {
                foreach (var item in Model.Columns)
                {
                    if (!item.IsVisible)
                        continue;

                    if (item.IsSum)
                    {
                        object value = null;
                        Model.Result?.Statis?.TryGetValue(item.Id, out value);
                        <SummaryCell>@value</SummaryCell>
                    }
                    else
                    {
                        <SummaryCell />
                    }
                }
            }
            @if (Model.HasAction)
            {
                <SummaryCell />
            }
        </SummaryRow>
    }
</AntTable>

@code {
    private AntTable<TItem> table;
    private bool isQuering = false;
    private string scrollX = "";
    private string scrollY => Model.FixedHeight ?? "1000px";

    [Parameter] public TableModel<TItem> Model { get; set; }

    protected override void OnInitialized()
    {
        var totalWidth = Model.Columns.Select(c => c.Width > 0 ? c.Width : 100).Sum();
        if (totalWidth > 1000)
            scrollX = totalWidth.ToString();
        Model.OnRefresh = RefreshTableAsync;
        base.OnInitialized();
    }

    private async Task RefreshTableAsync()
    {
        await InvokeAsync(() =>
        {
            if (Model.Criteria.IsQuery)
            {
                table?.ReloadData();
            }
            else
            {
                var query = table?.GetQueryModel();
                table?.ReloadData(query);
            }
        });
    }

    private async Task OnChange(QueryModel<TItem> query)
    {
        if (Model.OnQuery == null || isQuering)
            return;

        if (Config.IsClient)
        {
            isQuering = true;
            await OnChangeAsync(query);
            isQuering = false;
            return;
        }

        isQuering = true;
        await StateChangedAsync();
        await Task.Run(async () =>
        {
            await OnChangeAsync(query);
            isQuering = false;
            await StateChangedAsync();
        });
    }

    private async Task OnChangeAsync(QueryModel<TItem> query)
    {
        var watch = Stopwatcher.Start<TItem>();
        if (Model.Criteria.IsQuery)
            Model.Criteria.PageIndex = 1;
        Model.Criteria.PageIndex = query.PageIndex;
        Model.Criteria.PageSize = query.PageSize;
        if (query.SortModel != null)
        {
            var sorts = query.SortModel.Where(s => !string.IsNullOrWhiteSpace(s.Sort));
            Model.Criteria.OrderBys = sorts.Select(m => GetOrderBy(m)).ToArray();
        }
        Model.Criteria.StatisColumns = Model.Columns.Where(c => c.IsSum).Select(c => new StatisColumnInfo { Id = c.Id }).ToList();
        Model.Result = await Model.OnQuery?.Invoke(Model.Criteria);
        Model.SelectedRows = [];
        await Model.RefreshStatisAsync();
        watch.Write($"Changed {Model.Criteria.PageIndex}");
    }

    private async void OnRowClick(RowData<TItem> row)
    {
        if (Model.OnRowClick == null)
            return;

        await Model.OnRowClick.Invoke(row.Data);
    }

    private string GetOrderBy(ITableSortModel model)
    {
        //descend  ascend
        var sort = model.Sort == "descend" ? "desc" : "asc";
        var fieldName = model.FieldName;
        if (string.IsNullOrWhiteSpace(fieldName))
            fieldName = Model.Columns[model.ColumnIndex - 1].Id;
        return $"{fieldName} {sort}";
    }

    private static ColumnAlign GetColumnAlign(string align)
    {
        if (align == "center")
            return ColumnAlign.Center;
        else if (align == "right")
            return ColumnAlign.Right;
        return ColumnAlign.Left;
    }

    private static string GetColumnText(ColumnInfo item, object value)
    {
        var text = $"{value}";
        if (item.Type == FieldType.Date)
        {
            if (value is string)
                value = Utils.ConvertTo<DateTime?>(value);
            text = $"{value:yyyy-MM-dd}";
        }
        if (item.Type == FieldType.DateTime)
        {
            if (value is string)
                value = Utils.ConvertTo<DateTime?>(value);
            text = $"{value:yyyy-MM-dd HH:mm:ss}";
        }
        return text;
    }

    private string GetActionColor(string style) => style == "danger" ? "red-inverse" : "blue-inverse";
}